package com.player.dao;

import java.util.List;
import java.util.Map;

import com.google.appengine.api.datastore.QueryResultIterable;
import com.googlecode.objectify.Key;
import com.googlecode.objectify.Query;
import com.player.entity.Player;
import com.player.rest.exception.PropertyAlreadyExistsException;

public class PlayerDAO extends DAO {

	public static final String PROP_EMAIL = "email";
	public static final String PROP_PLAYERNAME_NORMALIZED = "playernameNormalized";

	/* pkg */PlayerDAO() {
	}

	/**
	 * @return Player or Null if not found
	 */
	public Player get(long id) {
		if (id == ID_NOT_EXISTING) {
			throw new IllegalArgumentException("id must be > 0");
		}
		return ofy().find(Player.class, id);
	}

	/**
	 * @return Players or Null if not all players found
	 */
	public Map<Long, Player> get(Long... ids) {
		for (Long id : ids) {
			if (id == ID_NOT_EXISTING) {
				throw new IllegalArgumentException("id must be > 0");
			}
		}

		Map<Long, Player> playersById = ofy().get(Player.class, ids);
		if (playersById.keySet().size() != ids.length) {
			return null; // not all players found!
		}

		return playersById;
	}

	public List<Player> getAll() {
		return ofy().query(Player.class).list();
	}

	/**
	 * Find by playername (ignorecase)
	 */
	public List<Player> findByPlayername(String playername) {
		String playernameNorm = playername.trim().toUpperCase();
		Query<Player> query = ofy().query(Player.class).filter(PROP_PLAYERNAME_NORMALIZED + " >=", playernameNorm)
				.filter(PROP_PLAYERNAME_NORMALIZED + " <", playernameNorm + "\uFFFD");
		List<Player> result = query.list();
		return result;
	}

	public Player create(String email, String playername) throws PropertyAlreadyExistsException {
		Player created = new Player(playername, email, "", "");
		ensurePlayerNotExists(created);
		ofy().put(created);
		return created;
	}

	public boolean existsEmail(String email) {
		return propertyExists(PROP_EMAIL, email);
	}

	private void ensurePlayerNotExists(Player p) throws PropertyAlreadyExistsException {
		if (propertyExists(PROP_PLAYERNAME_NORMALIZED, p.getPlayernameNormalized())) {
			throw new PropertyAlreadyExistsException("Player with playername \"" + p.getPlayername()
					+ "\" already exists.", PROP_PLAYERNAME_NORMALIZED, p.getPlayername());
		}
		if (propertyExists(PROP_EMAIL, p.getEmail())) {
			throw new PropertyAlreadyExistsException("Player with email \"" + p.getEmail() + "\" already exists.",
					PROP_EMAIL, p.getEmail());
		}

	}

	private boolean propertyExists(String name, String value) {
		QueryResultIterable<Key<Player>> fetchKeys = ofy().query(Player.class).filter(name, value).fetchKeys();
		return fetchKeys.iterator().hasNext();
	}
}
